﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using DetectingKinectSencor._40_Tools;
using System.IO;
using System.Windows.Media.Imaging;
using DetectingKinectSencor._10_ColorStream;

namespace DetectingKinectSencor._50_Evaluation.ViewModels.DetailedEvalaution
{
    public class MovementViewModelDetailed : Notifier
    {
         // Internal variable in which the model is saved in this class
        private PlotModel plotModel;
        private PlotModel plotModelTotalAmount;
        private PlotModel plotModelPercentage;

        private PlotModel tempPlotModelDataTime;
        private PlotModel tempPlotModelTotalAmount;
        private PlotModel tempPlotModelPercentage;

        private LineSeries timepointSerieMovementList;

        private DateTime captureTimeLastSequence;
        private int secondsForFileName;
        private int minutesForFileName;
        private TimeSpanAggregated timeSpan;
        private List<TimeSpanAggregated> timeSpanAggregated;
        private TimeSpan actualInterval;

        // Defines a timespan of 30 seconds
        private TimeSpan interval = new TimeSpan(0, 0, 60);
        private LineSeries timepointSerieMovementListPercentage;
        private double percentage;
        private TimeSpan actualIntervalUpperBound;

        // Important the UI needs to bind the Model to MovingPlotModel!!!
        public PlotModel MovementPlotModel
        {
            get { return plotModel; }
            set { plotModel = value; RaisePropertyChanged(() => MovementPlotModel); }
        }


        public PlotModel MovementPlotModelTotalAmount
        {
            get { return plotModelTotalAmount; }
            set { plotModelTotalAmount = value; RaisePropertyChanged(() => MovementPlotModelTotalAmount); }
        }

        public PlotModel MovementPlotModelPercentage
        {
            get { return plotModelPercentage; }
            set { plotModelPercentage = value; RaisePropertyChanged(() => MovementPlotModelPercentage); }
        }


        public MovementViewModelDetailed(DateTime lastElementCaptureTime, SnapshotManager snapshotManager)
        {
            tempPlotModelDataTime = new PlotModel();
            tempPlotModelTotalAmount = new PlotModel();
            tempPlotModelPercentage = new PlotModel();

            SetUpModelDetailed();
            LoadDataMovementDetailed(lastElementCaptureTime, snapshotManager);
        }


        private void SetUpModelDetailed()
        {

            // Define the legend for the date/time graph

            tempPlotModelDataTime.LegendTitle = "Legend";
            tempPlotModelDataTime.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelDataTime.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelDataTime.LegendPosition = LegendPosition.TopRight;
            tempPlotModelDataTime.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelDataTime.LegendBorder = OxyColors.Black;
            tempPlotModelDataTime.LegendFontSize = DesignOfGraphs.fontSizeDetailed;


            // Axes which shows the date when the speaker looked away
            TimeSpanAxis timeLineAxis = new TimeSpanAxis(AxisPosition.Bottom, "Timeline (mm:ss)", "mm:ss")
                                                        {
                                                            MajorGridlineStyle = LineStyle.Solid,
                                                            MinorGridlineStyle = LineStyle.Dot,
                                                            FontSize = DesignOfGraphs.fontSizeDetailed
                                                        };

            // Add the axes to the plot model
            tempPlotModelDataTime.Axes.Add(timeLineAxis);

            // Axes which shows the Amount of time the speaker stood on the same spot
            TimeSpanAxis timeSpanAxis = new TimeSpanAxis(AxisPosition.Left, "Not moved\n(mm:ss)", "mm:ss")
                                                  {
                                                      MajorGridlineStyle = LineStyle.Solid,
                                                      MinorGridlineStyle = LineStyle.Dot,
                                                      FontSize = DesignOfGraphs.fontSizeDetailed
                                                  };

            // Add the axes to the plot model
            tempPlotModelDataTime.Axes.Add(timeSpanAxis);





            // Define the legend for the bar graph

            tempPlotModelTotalAmount.LegendTitle = "Legend";
            tempPlotModelTotalAmount.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelTotalAmount.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelTotalAmount.LegendPosition = LegendPosition.BottomCenter;
            tempPlotModelTotalAmount.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelTotalAmount.LegendBorder = OxyColors.Black;
            tempPlotModelTotalAmount.LegendFontSize = DesignOfGraphs.fontSizeDetailed;

            // Axes for the bar graph
            CategoryAxis categoryAxis = new CategoryAxis();

            //            categoryAxis.MinorStep = 1;
            categoryAxis.Labels.Add("Total Amount");
            categoryAxis.FontSize  = DesignOfGraphs.fontSizeDetailed;

            tempPlotModelTotalAmount.Axes.Add(categoryAxis);
            tempPlotModelTotalAmount.LegendFontSize = DesignOfGraphs.fontSizeDetailed;



            // Define the legend for the percentage graph

            tempPlotModelPercentage.LegendTitle = "Legend";
            tempPlotModelPercentage.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelPercentage.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelPercentage.LegendPosition = LegendPosition.TopRight;
            tempPlotModelPercentage.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelPercentage.LegendBorder = OxyColors.Black;
            tempPlotModelPercentage.LegendFontSize = DesignOfGraphs.fontSizeDetailed;


            // Axes which shows the date when the speaker looked away
            TimeSpanAxis timeLineAxisPercentage = new TimeSpanAxis(AxisPosition.Bottom, "Timeline (mm:ss)", "mm:ss")
            {
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                MajorStep = interval.TotalSeconds,
                Angle = -50,
                AxisTitleDistance = 12,
                FontSize = DesignOfGraphs.fontSizeDetailed
            };

            // Add the axes to the plot model
            tempPlotModelPercentage.Axes.Add(timeLineAxisPercentage);

            // Axes which shows the Amount of time the speaker stood on the same spot
            LinearAxis timeSpanAxisPercentage = new LinearAxis(AxisPosition.Left, 0, 100, "Percent moved\n in one minute ")
            {
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                MinorStep = 5,
                MajorStep = 10,
                FontSize = DesignOfGraphs.fontSizeDetailed
            };

            // Add the axes to the plot model
            tempPlotModelPercentage.Axes.Add(timeSpanAxisPercentage);
        }






        public void LoadDataMovementDetailed(DateTime captureTime, SnapshotManager snapshotManager)
        {
            // Get the list with the viewingDirectionData
            MovingData movementList = EvaluationData.movingData;
            TimeSpan elapsedTime;



            this.captureTimeLastSequence = captureTime;



            // Defines the data/time graph

            timepointSerieMovementList = new LineSeries
            {
                StrokeThickness = 2,
                MarkerSize = 3,
                MarkerStroke = Graph.colors[1],
                MarkerType = Graph.markerTypes[1],
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Movement"),
                Smooth = false,
            };


            // Defines the bars of total Amount graph

            ColumnSeries columnSeriesMovement = new ColumnSeries();

            columnSeriesMovement.LabelFormatString = "{0}";
            columnSeriesMovement.StrokeThickness = 1;
            columnSeriesMovement.Title = "Movement";


            tempPlotModelTotalAmount.Series.Add(columnSeriesMovement);




            // Defines the percentag graph

            timepointSerieMovementListPercentage = new StairStepSeries
            {
                Color = OxyColors.Blue,
                VerticalLineStyle = LineStyle.Dash,
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Movement"),
                Smooth = false,
            };




            // Add the data points to movement data/time graph

            foreach (CaptureTime movement in movementList.trackingSequences)
            {
                if (captureTime == movement.captureTime)
                {

                    timeSpanAggregated = new List<TimeSpanAggregated>();

                    // The actualInterval starts at 0 seconds
                    actualInterval =  new TimeSpan(0,0,0);

                    // The upper bound starts at 60 seconds
                    actualIntervalUpperBound = interval;


                    // The first interval is 0-60
                    timeSpan = new TimeSpanAggregated(new TimeSpan(0, 0, 0), 0);


                    for (int i = 0; i < movement.timePoints.Count; i++)
                    {
                        // It is more intuitiv to see the actual elapsed time from the beginning then the actual time 
                        elapsedTime = movement.timePoints[i].timePoint - captureTime;

                        timepointSerieMovementList.Points.Add(new DataPoint(TimeSpanAxis.ToDouble(elapsedTime),
                                                                          TimeSpanAxis.ToDouble(movement.timePoints[i].timeSpan)));



                        // Add the timepoints which are in the interval to the list and calculate the percentage later
                        if (elapsedTime >= actualInterval && elapsedTime <= actualIntervalUpperBound)
                        {
                            // Add the time the speaker stood an the same spot
                            timeSpan.totalAmount++;
                        }
                        else
                        {
                            timeSpanAggregated.Add(timeSpan);

                            // Define the lower bound of the interval
                            actualInterval += interval;

                            // Define the upper bound of the interval
                            actualIntervalUpperBound += interval;

                            // Timespan object for the new interval
                            timeSpan = new TimeSpanAggregated(actualInterval, 0);
                            
                            // decrement the indexer that the data point is checked against the next interval
                            i--;
                        }
                    
                    }

                    if (timeSpanAggregated.Count != 0)
                    {
                        // If the loop was left before the last object was saved, save it
                        if (!(timeSpanAggregated[timeSpanAggregated.Count - 1].Equals(timeSpan)))
                        {
                            timeSpanAggregated.Add(timeSpan);
                        }
                    }


                    TimeSpan intervalPercentage = new TimeSpan(0,0,0);

                    for (int i = 0; i < timeSpanAggregated.Count; i++)
                    {

                        percentage = (100 * timeSpanAggregated[i].totalAmount) / movement.timePoints.Count;

                        timepointSerieMovementListPercentage.Points.Add(new DataPoint(
                                                         TimeSpanAxis.ToDouble(intervalPercentage),
                                                         percentage));
                        
                        // When using the step graph, the peek needs to be at the starting point 0,
                        // because the first interval is 0-60. This is why the saved interval in 
                        // timeSpanAggregated[i].timespan can not be used, because then would the first 
                        // peek be at 60! and the whole graph would be moved to the right.
                        intervalPercentage += interval;

                    
                    }

                     // Add a final point which closes the interval
                    timepointSerieMovementListPercentage.Points.Add(new DataPoint(
                                                                                TimeSpanAxis.ToDouble(intervalPercentage),
                                                                                0));

                    tempPlotModelDataTime.Series.Add(timepointSerieMovementList);

                    // ad the total Amount to the bar graph
                    columnSeriesMovement.Items.Add(new ColumnItem(movement.timePoints.Count));

                    tempPlotModelPercentage.Series.Add(timepointSerieMovementListPercentage);

                    break;
                }
            }

            //Saved the tempPlotModel to the plotModel than is the OnPropertyChanged executed and the UI is updated
            MovementPlotModel = tempPlotModelDataTime;
            MovementPlotModelTotalAmount = tempPlotModelTotalAmount;
            MovementPlotModelPercentage = tempPlotModelPercentage;




            // Event handler for the mous click
            timepointSerieMovementList.MouseDown += (s, e) =>
            {
                // only handle the left mouse button (right button can still be used to pan)
                if (e.ChangedButton == OxyMouseButton.Left)
                {
                    int indexOfNearestPoint = (int)Math.Round(e.HitTestResult.Index);


                    //var nearestPoint = timepointSerieOpenGesturesList.Transform(timepointSerieOpenGesturesList.Points[indexOfNearestPoint]);
                    //Console.WriteLine("neares point: " + nearestPoint);


                    foreach (CaptureTime movement in movementList.trackingSequences)
                    {
                        if (captureTimeLastSequence == movement.captureTime)
                        {
                            // Calculate the timePoint for the clicked point on the graph
                            double timePoint = timepointSerieMovementList.Points[indexOfNearestPoint].X;

                            for (int i = 0; i < movement.timePoints.Count; i++)
                            {
                                // calculate the timePoint for the openGesture timePoint
                                double elapsedTimeTemp = TimeSpanAxis.ToDouble(movement.timePoints[i].timePoint - captureTimeLastSequence);

                                if (elapsedTimeTemp == timePoint)
                                {
                                    DateTime tempTimePoint = movement.timePoints[i].timePoint;

                                    minutesForFileName = tempTimePoint.Minute;
                                    secondsForFileName = tempTimePoint.Second;


                                    for (int j = 0; j <= XMLproperties.secondsTillSnapshot; j++)
                                    {

                                        string filename = "Snapshots\\" +
                                                          tempTimePoint.Day +
                                                          "_" +
                                                          tempTimePoint.Month +
                                                          "_" +
                                                          tempTimePoint.Year +
                                                          "_" +
                                                          tempTimePoint.Hour +
                                                          "_" +
                                                          minutesForFileName +
                                                          "_" +
                                                          secondsForFileName +
                                                          ".jpg";

                                        if (File.Exists(filename))
                                        {

                                            Stream imageStreamSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                                            JpegBitmapDecoder decoder = new JpegBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                                            BitmapSource bitmapSource = decoder.Frames[0];

                                            WriteableBitmap wbitmap = new WriteableBitmap(bitmapSource);

                                            snapshotManager.update(wbitmap);
                                            break;
                                        }

                                        if ((secondsForFileName) > 60)
                                        {
                                            minutesForFileName++;
                                            secondsForFileName = 0;
                                        }
                                        else
                                        {
                                            secondsForFileName++;
                                        }
                                    }
                                    break;
                                }


                            }
                            break;
                        }
                    }
                }
            };


        }
    }
}
